package com.xqq.juc;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.LockSupport;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.LockSupport;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.LockSupport;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.CountDownLatch;
import java.lang.reflect.Field;

public class AQSStateDebugger {

    private static final ReentrantLock lock = new ReentrantLock();
    private static final List<Thread> workerThreads = new ArrayList<>();
    private static final AtomicInteger stateValue = new AtomicInteger(0);
    private static final List<String> queueInfo = new ArrayList<>();
    private static final CountDownLatch allWorkersDone = new CountDownLatch(4);
    private static volatile boolean shouldRun = true;

    // 打印AQS状态
    private static void printAQSState(String context) {
        // 获取锁状态
        boolean isLocked = lock.isLocked();
        boolean hasQueuedThreads = lock.hasQueuedThreads();
        int queueLength = lock.getQueueLength();
        int holdCount = lock.getHoldCount();

        // 获取锁的持有者
        Thread owner = null;
        try {
            // 使用反射获取锁的持有者
            Field exclusiveOwnerThreadField = ReentrantLock.class.getSuperclass()
                    .getDeclaredField("exclusiveOwnerThread");
            exclusiveOwnerThreadField.setAccessible(true);
            owner = (Thread) exclusiveOwnerThreadField.get(lock);
        } catch (Exception e) {
            // 如果反射失败，使用替代方法
            owner = Thread.currentThread().isAlive() && lock.isHeldByCurrentThread() ?
                    Thread.currentThread() : null;
        }

        // 构建队列信息
        queueInfo.clear();
        if (hasQueuedThreads) {
            for (Thread t : workerThreads) {
                if (t != Thread.currentThread() && lock.hasQueuedThread(t)) {
                    queueInfo.add(t.getName() + " (状态: " + t.getState() + ")");
                }
            }
        }

        // 打印状态
        System.out.printf("\n[%s] AQS状态 === state:%d 持有线程:%s 重入计数:%d 队列长度:%d%n",
                context,
                stateValue.get(),
                owner != null ? owner.getName() : "无",
                holdCount,
                queueLength);

        if (!queueInfo.isEmpty()) {
            System.out.println("等待队列:");
            for (String info : queueInfo) {
                System.out.println("  " + info);
            }
        }
    }

    static class LockWorker implements Runnable {
        private final String name;
        private final int workDuration;
        private final boolean shouldPark;
        private final CountDownLatch parkLatch = new CountDownLatch(1);

        public LockWorker(String name, int workDuration, boolean shouldPark) {
            this.name = name;
            this.workDuration = workDuration;
            this.shouldPark = shouldPark;
        }

        @Override
        public void run() {
            try {
                System.out.println(name + " ➡️ 尝试获取锁");

                lock.lock();
                stateValue.incrementAndGet();

                try {
                    System.out.println(name + " 🔐 成功获取锁");
                    printAQSState(name + "获取锁后");

                    // 模拟工作
                    System.out.println(name + " ⏳ 工作中(" + workDuration + "ms)...");
                    Thread.sleep(workDuration);

                    if (shouldPark) {
                        System.out.println(name + " 🅿️ 主动挂起自己");
                        parkLatch.countDown(); // 通知主线程已准备好挂起
                        LockSupport.park(); // 挂起自己
                        System.out.println(name + " 🔄 被唤醒");
                    }

                    System.out.println(name + " 🎯 工作完成");
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                } finally {
                    lock.unlock();
                    stateValue.decrementAndGet();
                    System.out.println(name + " 🔓 释放锁");
                    printAQSState(name + "释放锁后");
                }
            } finally {
                allWorkersDone.countDown(); // 标记任务完成
            }
        }

        public void awaitParkReady() throws InterruptedException {
            parkLatch.await();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        System.out.println("===== AQS状态调试器启动 =====");
        printAQSState("初始状态");

        // 创建工作线程实例
        LockWorker worker1 = new LockWorker("Worker-1", 2000, false);
        LockWorker worker2 = new LockWorker("Worker-2", 1000, true);
        LockWorker worker3 = new LockWorker("Worker-3", 1500, false);
        LockWorker worker4 = new LockWorker("Worker-4", 500, false);

        // 创建并启动工作线程
        workerThreads.add(new Thread(worker1, "Worker-1"));
        workerThreads.add(new Thread(worker2, "Worker-2"));
        workerThreads.add(new Thread(worker3, "Worker-3"));
        workerThreads.add(new Thread(worker4, "Worker-4"));

        // 启动所有工作线程
        for (Thread t : workerThreads) {
            t.start();
            Thread.sleep(100); // 确保线程按顺序启动
            printAQSState("启动 " + t.getName() + " 后");
        }

        // 监控线程：定期打印AQS状态
        Thread monitorThread = new Thread(() -> {
            while (shouldRun) {
                try {
                    printAQSState("监控线程");
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    break;
                }
            }
            System.out.println("监控线程结束");
        });
        monitorThread.setDaemon(true);
        monitorThread.start();

        // 等待Worker-2准备好挂起
        worker2.awaitParkReady();
        System.out.println("\nWorker-2已准备好挂起，主线程将唤醒它");

        // 唤醒Worker-2
        LockSupport.unpark(workerThreads.get(1));

        // 等待所有工作线程完成
        allWorkersDone.await();

        // 设置停止标志并等待监控线程结束
        shouldRun = false;
        Thread.sleep(500); // 给监控线程一点时间结束

        System.out.println("\n===== 所有工作线程完成 =====");
        printAQSState("最终状态");
    }
}